<?php

class pncSoapClient extends pncClient {
	var $client;
	var $id;

	function pncSoapClient($wsdl) {
		$this->client = new pncSoap($wsdl,array('trace'=>1));
		$this->id=1;
	}

	function editconfig($editdom) {
		try {
			$xml=$editdom->saveXML();
			$msg=array('message-id'=>$this->id++,
			'edit-config'=>array('target'=>array('running'=>''),
            'config'=>substr($xml, (strpos($xml, "\n")+1)),XSD_ANYXML));
			$res=$this->client->rpc($msg);
			return $this->client->getResDom();
		}	catch(SoapFault $e) {
			print $e;
		}
	}

	function get($xpath) {
		try {
			$msg=array('message-id'=>$this->id++,
			'get'=>array('source'=>array('running'=>''),
            'filter'=>array('type'=>'xpath',
			'select'=>"$xpath")));
			$res=$this->client->rpc($msg);			
			return $this->client->getResDom();
		}	catch(SoapFault $e) {
			print $e;
		}
	}

	function hello() {
		try {
			$hello=$this->client->hello(array (
                 'capabilities' => array (
                                           'urn:ietf:params:netconf:base:1.0',
                                           'urn:ietf:params:netconf:capability:xpath:1.0',
					   'urn:ietf:params:netconf:capability:writable-running:1.0'
	 				)));
		}	catch(SoapFault $e) {
			print $e;
		}
	}
}

class pncSoap extends SoapClient
{
	var $result;

	public function __doRequest($request, $location, $action, $version)
	{
		$this->result = parent::__doRequest($request, $location, $action, $version);
		return $this->result;
	}

	public function getResDom() {
		//Needed for fixing bug in PHP SOAP
		$dom=new domDocument();
		if(strlen($this->result)==0)
		die("Error: empty XML string\n");
		if(!$dom->loadXML($this->result))
		print "ERROR: ".$this->result."\n";
		$res=new domDocument();
		$reply=	$dom->getElementsByTagName("rpc-reply");
		$res->appendChild($res->importNode($reply->item(0),true));
		return $res;
	}
}


abstract class pncClient {
	abstract function editconfig($editdom);
	abstract function get($xpath);
	abstract function hello();
}

class pncSshClient extends pncClient {

	var $pipes,$ssh;
	var $helloxml;
	var $send;

	function editconfig($editdom) {
		$dom = new DomDocument;
		$rpc=$dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","rpc");
		$dom->appendChild($rpc);
		$rpc->appendChild($this->_addAttr($dom,"message-id",1));
		$get=$dom->createElement("edit-config");
		$rpc->appendChild($get);
		$source=$dom->createElement("target");
		$get->appendChild($source);
		$source->appendChild($dom->createElement("running"));
		$cfg=$dom->createElement("config");
		$get->appendChild($cfg);
		$cfg->appendChild($dom->importNode($editdom->firstChild,true));
		$this->_sendXML($dom);

		return $this->_readXML();
	}

	function get($xpath) {
		$dom = new DomDocument;
		$rpc=$dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","rpc");
		$rpc->appendChild($this->_addAttr($dom,"message-id",1));
		$dom->appendChild($rpc);
		$get=$dom->createElement("get");
		$rpc->appendChild($get);
		$source=$dom->createElement("source");
		$get->appendChild($source);
		$source->appendChild($dom->createElement("running"));
		$filter=$dom->createElement("filter");
		$filter->appendChild($this->_addAttr($dom,"type","xpath"));
		$filter->appendChild($this->_addAttr($dom,"select",$xpath));
		$get->appendChild($filter);
		$this->_sendXML($dom);
		$ret=$this->_readXML();
		return $ret;
	}

	private function _addAttr($dom,$name,$value) {
		$attr=$dom->createAttribute($name);
		$attr->appendChild($dom->createTextNode($value));
		return $attr;
	}

	function pncSshClient($host) {
		$descriptorspec = array(
		0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
		1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
		2 => array("pipe", "w") // stderr is a pipe that the child will write to
		);
		
		$this->ssh=proc_open("/usr/bin/ssh -C -s $host netconf",$descriptorspec,$this->pipes);
		if(!is_resource($this->ssh))
		die("Could not connect to server");

	}

	private function fgetsTimeout(&$in,$timeout=false) {
		if(!$timeout)
		return fgets($in);
		if ( stream_select($read = array($in),$write=NULL,$except=NULL,10) ) return fgets($in);
		else return FALSE;
	}

	private function _readXML($timeout=false) {
		$xmlstr="";
		while($str=$this->fgetsTimeout($this->pipes[1],$timeout)) {
			if(preg_match("/\]\]>\]\]/",$str))
			break;
			$xmlstr.=$str;
		}
		if($str==false) {
			print "Error: empty string\n";
			return false;
		}
		$dom=new domDocument();
		if(strlen($xmlstr)==0)
		die("Error: empty XML string\n");
		if(!$dom->loadXML($xmlstr))
		print "Could not load XML: $xmlstr\n";
			
		$this->checkError($dom);
		return $dom;
	}

	private function checkError($dom) {
		$xp=new domxpath($dom);
		$xp->registerNamespace("nc","urn:ietf:params:xml:ns:netconf:base:1.0");
		$res=$xp->query("//nc:rpc-error");
		if(!$res or $res->length>0)
		print $dom->saveXML();
	}

	private function _sendXML($dom) {
		print $dom->saveXML()."\n";
		fwrite($this->pipes[0],$dom->saveXML()."]]>]]>\n");
	}


	function __destruct() {
		fclose($this->pipes[0]);
		fclose($this->pipes[1]);
		proc_close($this->ssh);
	}

	function hello()
	//Send hello message
	{
		//Read hello message
		$this->helloxml=$this->_readXML(true);
		if(!$this->helloxml)
		die("ERROR: Did not receive hello message from MA\n");

		$dom = new DomDocument;
		$hello=$dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","hello");
		$dom->appendChild($hello);
		$capabilities=$dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","capabilities");
		$hello->appendChild($capabilities);
		$capabilities->appendChild($dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","capability","urn:ietf:params:xml:ns:netconf:base:1.0"));
		$capabilities->appendChild($dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","capability","urn:ietf:params:netconf:capability:xpath:1.0"));
		$this->_sendXML($dom);
	}
}

function printQuery($maid,$source,$query,$cvs=false,$header=true) {
	global $client;
	$qxp=new domxpath($query);
	$qxp->registerNamespace("pn","http://stager.uninett.no/perfsonarnc/1.0");
	$report=$qxp->query("//pn:report")->item(0)->textContent;
	$type=$qxp->query("//pn:type")->item(0)->textContent;
	$view=$qxp->query("//pn:view")->item(0)->textContent;

	if($header) {
		//Create headers
		$headers=$client->get("//pn:dataSource[pn:id='$source']/pn:reportsInfo/pn:reportInfo[pn:id='$report']/pn:reportTypes/pn:reportType[pn:type='$type']/pn:views/pn:view[pn:id='$view']");
		$xp=new domxpath($headers);
		$xp->registerNamespace("pn","http://stager.uninett.no/perfsonarnc/1.0");
		$names=$xp->query("//pn:topHeader/pn:name");
		$top="";
		$sub="";
		$pre="";
		foreach($names as $name) {
			$top.=$name->textContent."\t";
			$subnames=$xp->query("//pn:topHeader[pn:name='".$name->textContent."']/pn:subHeader/pn:name");
			$count=0;
			foreach($subnames as $s) {
				$top.="\t";
				$sub.=$s->textContent."\t";
				$count++;
			}
			if($count==0)
			$pre.="\t";
		}
	}
	//Print data
	$str="";
	$timeperiods=$qxp->query("//pn:result/pn:timePeriod");
	foreach($timeperiods as $tp) {
	  $resolution=$tp->getElementsByTagNameNS("http://stager.uninett.no/perfsonarnc/1.0",'resolution')->item(0)->textContent;
	  $timestamp=$tp->getElementsByTagNameNS("http://stager.uninett.no/perfsonarnc/1.0",'timestamp')->item(0)->textContent;
	  $str.="Resolution: $resolution  Timestamp: $timestamp\n";
	  if($type=="table" or $type=="singleTable") {
	    $obspoints=$qxp->query("//pn:result/pn:timePeriod[pn:resolution=$resolution and pn:timestamp=$timestamp]/pn:obsPoint/pn:id");
	    foreach($obspoints as $o) {
	      $str.="Obspoint id: ".$o->textContent."\n";
	      if($header)
		$str.="$top\n$pre$sub\n";
	      $rows=$qxp->query("//pn:result/pn:timePeriod[pn:resolution=$resolution and pn:timestamp=$timestamp]/pn:obsPoint[pn:id=".$o->textContent."]/pn:rows/pn:row/pn:index");
	      foreach($rows as $row) {
		$data=$qxp->query("//pn:result/pn:timePeriod[pn:resolution=$resolution and pn:timestamp=$timestamp]/pn:obsPoint[pn:id=".$o->textContent."]/pn:rows/pn:row[pn:index=".$row->textContent."]/pn:datum");
		foreach($data as $datum)
		  if($cvs)
		    $str.=preg_replace("/,/","\,",$datum->textContent).";";
		  else $str.=$datum->textContent."\t";
		$str=rtrim($str,";");
		$str.="\n";
	      }
	    }
	  } elseif($type=="singleOverview") {
	    $rows=$qxp->query("//pn:result/pn:timePeriod[pn:resolution=$resolution and pn:timestamp=$timestamp]/pn:rows/pn:row/pn:index");
	    foreach($rows as $row) {
	      $oid=$qxp->query("//pn:result/pn:timePeriod[pn:resolution=$resolution and pn:timestamp=$timestamp]/pn:rows/pn:row[pn:index=".$row->textContent."]/pn:obsPoint");
	      $str.=$oid->item(0)->textContent.";";
	      $data=$qxp->query("//pn:result/pn:timePeriod[pn:resolution=$resolution and pn:timestamp=$timestamp]/pn:rows/pn:row[pn:index=".$row->textContent."]/pn:datum");
	      foreach($data as $datum)
		if($cvs)
		  $str.=preg_replace("/,/","\,",$datum->textContent).";";
		else $str.=$datum->textContent."\t";
	      $str=rtrim($str,";");
	      $str.="\n";
	    }
	  }
	}
	print $str;
}

/*
function readline($prompt = "") {
	print $prompt;
	$out = "";
	$key = "";
	$key = fgetc(STDIN); //read from standard input (keyboard)
	while ($key != "\n") //if the newline character has not yet arrived read another
	{
		$out .= $key;
		$key = fread(STDIN, 1);
	}
	return $out;
}
*/

function xmlpp($xml) {
	$xml_obj = new SimpleXMLElement($xml);
	$level = 4;
	$indent = 0; // current indentation level
	$pretty = array();

	// get an array containing each XML element
	$xml = explode("\n", preg_replace('/>\s*</', ">\n<", $xml_obj->asXML()));

	// shift off opening XML tag if present
	if (count($xml) && preg_match('/^<\?\s*xml/', $xml[0])) {
		$pretty[] = array_shift($xml);
	}

	foreach ($xml as $el) {
		if (preg_match('/^<([\w])+[^>]*[^>\/]>$/U', $el)) {
			// opening tag, increase indent
			$pretty[] = str_repeat(' ', $indent) . $el;
			$indent += $level;
		} else {
			if (preg_match('/^<\/.+>$/', $el)) {
				$indent -= $level;  // closing tag, decrease indent
			}
			if ($indent < 0) {
				$indent += $level;
			}
			$pretty[] = str_repeat(' ', $indent) . $el;
		}
	}
	$xml = implode("\n", $pretty);
	return $xml;
}
?>